package com.monster.valid.utils;

import com.monster.utils.StringUtils;
import com.monster.utils.TimeUtils;
import com.monster.valid.common.ValidExceptionEnum;
import com.monster.valid.regex.RegexEnum;
import com.monster.valid.regex.RegexUtils;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;

/**
 * 身份证校验
 *
 * @author kuang
 */
public class ValidIdCardUtils {
    private ValidIdCardUtils() {
    }

    public static final int length15 = 15;
    public static final int length18 = 18;
    /**
     * 身份证对应省份标识
     */
    public static final Map<String, String> areaCode = new HashMap<>();

    static {
        areaCode.put("11", "北京");
        areaCode.put("12", "天津");
        areaCode.put("13", "河北");
        areaCode.put("14", "山西");
        areaCode.put("15", "内蒙古");
        areaCode.put("21", "辽宁");
        areaCode.put("22", "吉林");
        areaCode.put("23", "黑龙江");
        areaCode.put("31", "上海");
        areaCode.put("32", "江苏");
        areaCode.put("33", "浙江");
        areaCode.put("34", "安徽");
        areaCode.put("35", "福建");
        areaCode.put("36", "江西");
        areaCode.put("37", "山东");
        areaCode.put("41", "河南");
        areaCode.put("42", "湖北");
        areaCode.put("43", "湖南");
        areaCode.put("44", "广东");
        areaCode.put("45", "广西");
        areaCode.put("46", "海南");
        areaCode.put("50", "重庆");
        areaCode.put("51", "四川");
        areaCode.put("52", "贵州");
        areaCode.put("53", "云南");
        areaCode.put("54", "西藏");
        areaCode.put("61", "陕西");
        areaCode.put("62", "甘肃");
        areaCode.put("63", "青海");
        areaCode.put("64", "宁夏");
        areaCode.put("65", "新疆");
        areaCode.put("71", "台湾");
        areaCode.put("81", "香港");
        areaCode.put("82", "澳门");
        areaCode.put("91", "国外");
    }

    /**
     * 定义数组加权因子
     */
    private static final int[] wf = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    /**
     * 定义数组存放校验码
     */
    private static final String[] cc = {"1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2"};

    /**
     * 15位身份证好转换位18位身份证号码
     *
     * @param idCard 15位身份证
     * @return 18位的身份证号码
     */
    public static String to18(String idCard) {
        if (idCard == null || idCard.length() != length15) {
            return "";
        }
        int sum = 0;
        idCard = idCard.substring(0, 6) + "19" + idCard.substring(6);
        // 17位数字和系数相乘，结果相加
        for (int i = 0; i < 17; i++) {
            sum = sum + Integer.parseInt(idCard.substring(i, i + 1)) * wf[i];

        }
        return idCard + cc[(sum % 11)];
    }

    /**
     * 身份证校验
     * @param idCard 身份证
     * @return boolean
     */
    public static boolean check(String idCard) {
        if (StringUtils.isEmpty(idCard)) {
            return false;
        }
        if (idCard.length() == length15) {
            idCard = to18(idCard);
        }
        if (idCard.length() != length18) {
            return false;
        }
        // 前17位数字
        if (!RegexUtils.isMatch(RegexEnum.NUMBER.getPattern(), idCard.substring(0, 16))) {
            return false;
        }
        // 判断地区码
        if (!areaCode.containsKey(idCard.substring(0, 2))) {
            return false;
        }
        // 判断，和现在的时间不能相差150（成老妖怪了）

        // 格式校验
        String birthday = idCard.substring(6, 14);
        try {
            LocalDate.parse(birthday, TimeUtils.getFormatter(TimeUtils.yyyyMMdd));
        } catch (Exception e) {
            return false;
        }
        // 生日时间不得晚于当前日期
        int birthdayDate = Integer.parseInt(birthday.substring(0, 4));
        int currentDate = Integer.parseInt(TimeUtils.format(TimeUtils.yyyy));
        if (birthdayDate > currentDate || (currentDate - birthdayDate) > 150) {
            return false;
        }
        // 校验位校验
        int sum = 0;
        for (int i = 0; i < 17; i++) {
            sum = sum + Integer.parseInt(idCard.substring(i, i + 1)) * wf[i];
        }
        if (!idCard.substring(17).equals(cc[(sum % 11)])) {
            return false;
        }
        return true;
    }

}
